package com.zeyu.framework.tools;

import com.beust.jcommander.internal.Lists;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.List;

/**
 * 代码行数统计工具
 */
public class CodeCounter {

    // ================================================================
    // Constants
    // ================================================================

    // ================================================================
    // Fields
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(CodeCounter.class);

    // ================================================================
    // Constructors
    // ================================================================

    // 文件数
    private static long files = 0;
    // 代码行数
    private static long codeLines = 0;
    // 注释行数
    private static long commentLines = 0;
    // 空白行数
    private static long blankLines = 0;

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 打印代码统计信息
     */
    public void printCountInfo() {
        // 文件列表
        List<File> fileList = Lists.newArrayList();

        String file = CodeCounter.class.getResource("/").getFile();
        String path;
        if (file.contains("target/test-classes")) {
            // if test not in web classes
            path = file.replace("target/test-classes", "src/main/java");
        } else {
            // web running
            path = file.replace("webapp/WEB-INF/classes", "java");
        }

        logger.info("count path is {}", path);

        // 获取所有文件
        getFile(new File(path), fileList);
        // 匹配java格式的文件
        fileList.stream().filter(item -> item.getName().matches(".*\\.java$")).forEach(item -> {
            count(item);
            logger.info("java file is {}", item);
        });

        logger.info("统计文件：{}" + files);
        logger.info("代码行数：{}" + codeLines);
        logger.info("注释行数：{}" + commentLines);
        logger.info("空白行数：{}" + blankLines);
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    /**
     * 获得目录下的文件和子目录下的文件
     *
     * @param file 目录
     */
    private static void getFile(File file, List<File> fileList) {
        if (fileList == null) {
            fileList = Lists.newArrayList();
        }
        // 列表
        File[] childList = file.listFiles();
        if (childList != null && childList.length > 0) {
            for (File child : childList) {
                if (child.isDirectory()) {
                    // 递归
                    getFile(child, fileList);
                } else
                    fileList.add(child);
            }
        }
    }

    /**
     * 统计方法
     *
     * @param file 统计文件
     */
    private static void count(File file) {
        BufferedReader br = null;
        // 开始结束标志
        boolean flag = false;
        try {
            br = new BufferedReader(new FileReader(file));
            String line;
            while ((line = br.readLine()) != null) {
                line = line.trim(); // 除去注释前的空格
                if (line.matches("^[ ]*$")) { // 匹配空行
                    blankLines++;
                } else if (line.startsWith("//")) {
                    commentLines++;
                } else if (line.startsWith("/*") && !line.endsWith("*/")) {
                    commentLines++;
                    flag = true;
                } else if (line.startsWith("/*") && line.endsWith("*/")) {
                    commentLines++;
                } else if (flag) {
                    commentLines++;
                    if (line.endsWith("*/")) {
                        flag = false;
                    }
                } else {
                    codeLines++;
                }
            }
            files++;
        } catch (IOException e) {
            logger.error("", e);
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.error("", e);
                }
            }
        }
    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================
}
